# _*_ coding: utf-8 _*_
"""
Time:     2024/8/22
Author:   2051261
File:     check.py
"""
import logging
from enum import Enum
from typing import Dict, Any, List, Union

from extractor.const import Mark
from extractor.utils.common_func import list_elements_to_lowercase
from extractor.const import ContextKey

logger = logging.getLogger(__name__)


class CheckType(Enum):
    IS_NOT_NONE = "is_not_none"
    IS_NOT_EMPTY_STR = "is_not_empty_str"
    IS_INT = "is_int"
    IS_FLOAT = "is_float"
    IS_STR = "is_str"
    VALUE_NOT_IN_LIST = "value_not_in_list"


async def is_not_none(data: Dict[str, Any], columns: list[str], **kwargs) -> Union[bool, int]:
    """
    检查指定列不为 None
    :param data: 数据源
    :param columns: 检查的列
    :param kwargs:
    [column1,
    columns2,
    ]
    :return:
    """
    for col in columns:
        if data[col] is None:
            return Mark.VALUE_NOT_NONE.value
    return True


async def is_not_empty_str(data: Dict[str, Any], columns: list[str], **kwargs) -> Union[bool, int]:
    """
    检查指定列不为空字符串
    :param data: 数据源
    :param columns: 检查的列
    :param kwargs:
    :return:
    """
    for col in columns:
        if data[col] == "":
            return Mark.NOT_EMPTY_STR.value
    return True


async def is_int(data: Dict[str, Any],  columns: list[str], **kwargs) -> Union[bool, int]:
    """
    检查指定列 数据类型为 int
    :param data: 数据源
    :param columns: 检查的列
    :param kwargs:
    :return:
    """
    for col in columns:
        try:
            int(data[col])
        except ValueError:
            return Mark.NOT_INT.value
    return True


async def is_float(data: Dict[str, Any], columns: list[str], **kwargs) -> Union[bool, int]:
    """
    检查指定列为 float
    :param data: 数据源
    :param columns: 检查的列
    :param kwargs:
    :return:
    """
    for col in columns:
        try:
            float(data[col])
        except ValueError:
            return Mark.NOT_FLOAT.value
    return True


async def is_str(data: Dict[str, Any],  columns: list[str], **kwargs) -> Union[bool, int]:
    """
    检查指定列为字符串
    :param data:
    :param columns: 检查的列
    :param kwargs:
    :return:
    """
    for col in columns:
        if not isinstance(data[col], str):
            return Mark.NOT_STR.value
    return True


async def value_not_in_list(data: Dict[str, Any], columns: list[str], values: list, **kwargs) -> Union[bool, int]:
    """
    检查指定的列值是否在指定值中
    :param data: 数据源
    :param columns: 检查的列
    :param values: 值列表
    :param kwargs:
    :return:
    """
    for col in columns:
        if data[col] in values:
            return Mark.NOT_IN_EXPECT_LIST.value
    return True


async def _check_column_in_data(data: Dict[str, Any], columns: list):
    if not isinstance(columns, list):
        raise ValueError(f"column: {columns} is not list")
    for col in columns:
        if col not in data:
            raise KeyError(f"col: {col} is not data: {data}")


async def validate_data(data: Dict[str, Any], checks: List[Dict[str, Any]]) -> Dict:
    """
    根据检查类型验证数据。

    :param data: 包含数据的字典
    :param checks: 检查类型
    [
            {
                "operate_func": "value_not_in_list",  # 检查使用的函数
                "kwargs": {  # 必要参数
                    "ref_column": "ref_column" 脏数据中村粗源数据主键的列
                    "ref_from_column": "znz_id",  # 源数据主键列
                    "mark_column": "mark_column",  # 清洗错误值b
                    "mark_value": "1"  # 清洗错误值
                    "columns": [],检查的列
                }
            },
            {
                "operate_func": "is_str",  #
                "kwargs": {
                    "ref_column": "salary",
                    "ref_from_column": "reference_id",
                    "mark_column": "status",
                    "mark_value": "invalid_salary"
                }
            }
        ]
    """
    operate_functions = {
        CheckType.IS_NOT_NONE: is_not_none,
        CheckType.IS_NOT_EMPTY_STR: is_not_empty_str,
        CheckType.IS_INT: is_int,
        CheckType.IS_FLOAT: is_float,
        CheckType.IS_STR: is_str,
        CheckType.VALUE_NOT_IN_LIST: value_not_in_list,
    }
    dirty = {}
    for item in checks:
        kwargs = item["kwargs"]
        operate_func = CheckType(item["operate_func"])  # 将 type 转换为 CheckType 枚举
        check_func = operate_functions.get(operate_func)
        if check_func is None:
            raise ValueError(f"Unsupported CheckType: {operate_func}")
        # 所有需要检查的列必须在 源数据中, 转换成小写形式
        if kwargs.get("columns"):
            kwargs["columns"] = await list_elements_to_lowercase(kwargs["columns"])
            _ = _check_column_in_data(data, kwargs["columns"])
        check_result = await check_func(data, **kwargs)
        if check_result is not True:
            dirty[kwargs["ref_column"]] = data[kwargs["ref_from_column"]]
            dirty[kwargs["mark_column"]] = check_result
            break

    return {ContextKey.DIRTY: dirty}
